Getters and Setters are evil
Getters and Setters are Evil
Downloads
Getters and Setters are Evil (Article)
Introduction
Since I started programming in Java in 2001, I have read so much about encapsulation. The Internet has become replete with Java articles and lessons teaching the basics of encapsulation in the form of declaring some class with private fields and public getters and setters.
Typical Examples of Encapsulation
Many Java books would show something like this to demonstrate encapsulation:
public class Car { private double gallonsOfFuel; private double milesPerGallon; public void setGallonsOfFuel(double gallonsOfFuel) { this.gallonsOfFuel = gallonsOfFuel; } public double getGallonsOfFuel() { return gallonssOfFuel; } public void setMilesPerGallon(double milesPerGallon) { this.milesPerGallon = milesPerGallon; } public double getMilesPerGallon() { return gallonsOfFuel; } }
Example 1
As many such introductory articles posit, since gallonsOfFuel is private, you need to add some additional logic like decreasing gallonsOfFuel by some amount every time getGallonsOfFuel() is called. This would then be considered a well-encapsulated Car class, i.e., the client would have to minimally change any code in other classes if functionality in the Car class was changed. However, this is not the case. Take a look at the travelMaxDistance() function below. Just how much better is the example with getters and setters (Example 2) than one using public fields (Example 3)?:
public class CarService { public void travelMaxDistance(Car car) { System.out.println(“Car traveled “ + maxDistance(car) + “ miles.”); } private double maxDistance(Car car) { return car.getGallonsOfFuel() * car.getMilesPerGallon(); } }
Example 2
public class CarService { public void travelMaxDistance(Car car) { System.out.println(“Car traveled “ + maxDistance(car) + “ miles.”); } private double maxDistance(Car car) { return car.gallonsOfFuel * car.milesPerGallon; } }
Example 3
As you can hopefully see, it isn’t any better at all! If you are trying to code in an object-oriented manner, as you should when using the Java language, you shouldn’t be violating encapsulation. Both of these examples violate encapsulation heavily and Example 2 represents what Martin Fowler calls an Anemic Domain Model.
Getters and Setters Are Evil
In my opinion, modern development environments have made the misuse of getters and setters all too easy by introducing automated getter and setter generation. When people start learning programming, they often find themselves introduced to auto-generated getters and setters in their IDE. One click, and people think their class is done and follows encapsulation rules when in fact it couldn’t be any farther from the truth. Just because you have the power to create getters and setters with a single click, doesn’t mean you’re wielding your power wisely.
In cases where you are modelling some complex business behavior between objects, try to avoid automated code generation, especially getter and setter generation, as much as possible. Design your entities by adding public attributes only when needed. View your entities from the perspective of its clients. Methodologies like test-driven development easily allow the design of classes with a focus on how a client can use the code – with tests driving and verifying the design. The misuse of automatic getter and setter generation is often a symptom of a poor design – often resulting in monolithic, unmanageable “spaghetti code”.
Proper Encapsulation
What methods would a client of your class need? Would a client be interested in the relationship between fuel and miles per gallon? If so, design for it. Make it as easy as possible for a possible client of your entity. Provide the fewest possible public methods your client needs. Do the work for your client internally. Don’t force your client to get his hands dirty. A real-world analogy would be a counter at a restaurant. You as a customer shouldn’t need to (and in many cases aren’t allowed to) know how your order is handled, only that the food comes out right. This is, roughly speaking, how encapsulation is supposed to play out. If a client was getting his hands dirty and preparing the meal himself, what would be the point of the restaurant? Think of your code in the same way.
As much as possible, try not to return raw data as directly stored in your entities’ private fields. Always try to add some value for your clients. As an example, given that calling travelMaxDistance() uses all of our Car class’ private fields, why not move the logic to the Car class so that clients would not need to know how our Car stores fuel and miles per gallon data? Doing so would have the net effect of reducing the amount of Car’s public methods, which would make it easier to make changes to the car class. A smaller, more meaningful number of public methods is always preferable to multiple public methods. To this end, we could move our calculation of the maximum travel distance to our Car class itself:
public class Car { private double gallonsOfFuel; private double milesPerGallon; public Car(double gallonsOfFuel, double milesPerGallon) { this.gallonsOfFuel = gallonsOfFuel; this.milesPerGallon = milesPerGallon; } public double maxDistance() { return gallonsOfFuel * milesPerGallon; } }
Example 4
We could then easily rewrite our CarService class’s previous travelMaxDistance() method as follows:
public void travelMaxDistance(Car car) { System.out.println(“Car traveled “ + car.maxDistance() + “ miles.”); }
Example 5
Note that the code now reads better as it clearly speaks the language of the business and solves their problem more precisely.
If you go back and look at the original code in Example 1 and Example 2 it is much less precise. The Car class was cluttered with simple but unnecessary code that has to be understood and maintained for no reason. You might question my changes in Example 4 since you might not think they are necessary for such a small code sample, but even there it makes our code clearer and precise and lets us see the actual important aspects of the code easily.
As a final note, I’d like to highlight that we didn’t add the “get” prefix to our maxDistance identifier as it decreases the readability of our code and shifts the code from an Object Oriented Design to a more procedural machine-like model.
These tiny changes, when applied rigorously to all your entities, will radically improve the readability and usability of your code. For an extensive guide that extends many of the points that a briefly talked about in this article, I would suggest reading up on Eric Evans’ Domain-Driven Design: Tackling Complexity in the Heart of Software.
[mc4wp_form]
Well I totally disagree with this point of view. I always use getters and setters, here is why;
I see ease of future refactoring of classes as one of the primary advantages of getters and setters.
In Example you have class Person which got a Physical Address and Email field stuck into it in your initial problem domain model both as Strings. Later on someone decides that a person can be associated with multiple Physical Addresses and wants the zip code as an integer, and that the domain part of the email address becomes important. With getters and setters this code is easy refactored, so that only the Person class needs changes, since the getter and setter signature can remain backward compatible.
With out getters and setters this change would involve all client code that uses the Person class, a maintenance nightmare! This ability to adapt to requirements changes is one of the tenements of OO programming!
Maintenance is roughly 80% of most software projects (from a slashdot.org article roughly 15 years ago), therefore Maintenance is very important design consideration. If you use field names directly refactoring is impossible with almost all current automated tools.
I think I failed to explain my point properly in your case.
My point was not to completly remove all public methods that allow to retrieve data from an object.
In a nutshell, my point was:
To not use the “auto generate getters and setters” feature of your IDE. In other words, don’t provide getters and setters for every private attribute.
Only provide what is really NEEDED truly. Plus, see every public method as a thread – so think twice before adding a method.
If you have a class Name with private firstName and private lastName it might be better to provide one method “fullName()” instead of two methods
“firstName()” and “lastName()” – and you see, I also avoid the “get” and “set in a methods name. Sometimes I do use them, if it is really a technical aspect, but in the majority of cases the natural language is not like “getFullName” but “fullName()” reads so much nicer and is also shorter.
I hope this helped to clarify my point.
Nice one. I liked the idea of using fullName() instead of getFullName() and setFullName(). Makes more sense.
I’d love to see classes with clean code but some other libraries e.g. some JSON parser/serializer relies on getter/setter to play with your class, this is my main concern of *NOT* using getter/setter
There are some (legacy) libraries that do require getters and setters.
Sometimes you just comply, and sometimes you could map to and from your own class to the bean (with getters and setters), or wrap the bean.
I have moved away from getters & setters, but not just because the whole encapsulation premise of them seems to be just so much fluff, but because I now treat many of my “domain” objects as simple immutable data structures, or sometimes as tuples, with almost no behavior beyond bare bones object methods (hashCode, equals, toString) that do not mutate the object.
I used to create domain objects with getters/setters/cloning/etc., maybe some domain behavior, property listeners, etc.
I found that these domain objects, when used in different contexts (server, client, etc.), needed different behavior that wasn’t easy to resolve in the class itself. E.G., most devs would agree that you don’t try to build view behavior into a model object, or persistence for that matter. So why try to build in business rules if the rules would change in a different context (and in a business app, they often do – e.g., the model of some domain object could easily change in different apps, but the structure of the data could be exactly the same).
So I often try to keep the behavior in a domain object to a the minimum.
You probably should give a nod to Alan Holub, who wrote that get/set is evil in his article “Extends is Evil” back in 2003. His get/set article is still online: http://www.javaworld.com/article/2073723/core-java/why-getter-and-setter-methods-are-evil.html
Well the term “getters and setters are evil” is indeed not new, it can be found countless times online – and for a reason – a) because it’s true, and b) because it sticks. I had this title in mind years ago, until I finally wrote the article 🙂
Great job.
In essence you are right, a bean’s internal storage and external properties do not need to match one-on-one. However, that does not mean that a bean should not / cannot have properties at all. A car can very well have a “milesPerGallon” property, no matter how it is stored internally, but because it makes sense for a car to have that property.
And even though the “maxDistance()” method reads better than the getter variant, unfortunately the get-prefix is the way how bean properties are defined in java. So I agree with you, but still would use get/set prefixes. They only should be used with proper consideration; that is the anti pattern.
well as always, it depends. If you need “milesPerGallon” then you would provide a public method providing it – in my example I didn’t need it, so I didn’t provide it. You always just provide the bare minimum needed, no less, no more. Regarding get, again it depends. Are we talking about retrieving an attribute from a simple entity? In this case, get doesn’t really add any information, rather then “hey this is data retrieved”.
However, now on the other hand, imagine you you a “Repository” class – to retrieve data from a persistent storage like a database – there “get…” actually tells a story – we are retrieving data. Further I differentiate between “find” and “get” in this case. “find” means “may return null” while “get” means will guarantee to return value, or throw a RuntimeException.
Good article. These conceps should be used as introdutory OO encapsulation in Java. The old “attributes are private and all of them has getters and setters” should be part of the past.
Thanks Marcelo. Actually, I think I did exactly that (or at least partially). Read my article about access and non access modifiers in Java:
https://marcus-biel.com/access-and-non-access/
Nice parable to restaurant. I would like also point to famous, thorough article on getters and setters: http://www.javaworld.com/article/2073723/core-java/why-getter-and-setter-methods-are-evil.html
Nice article!!! Also enjoy your video on equals and hashCode contracts – nicely done
nice article!